package dao

import (
	"context"
	"encoding/json"
	"strconv"
	"user_srv/basic/config"
	__ "user_srv/basic/userproto"
	"user_srv/handler/models"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"gorm.io/gorm"
)

// GetRiskRulesProto 获取风控规则列表（Proto接口）
func GetRiskRulesProto(ctx context.Context, req *__.GetRiskRulesReq) (*__.GetRiskRulesResp, error) {
	// 参数验证
	if req.Pagination == nil {
		return nil, status.Errorf(codes.InvalidArgument, "pagination is required")
	}
	if req.Filter == nil {
		return nil, status.Errorf(codes.InvalidArgument, "filter is required")
	}

	// 规范化分页参数
	page := req.Pagination.Page
	if page <= 0 {
		page = 1
	}
	pageSize := req.Pagination.PageSize
	if pageSize <= 0 {
		pageSize = 10
	} else if pageSize > 100 {
		pageSize = 100
	}

	// 调用现有方法
	rules, total, err := GetRiskRules(ctx, req.Filter.Name, req.Filter.Status, req.Filter.Priority, req.Filter.Scene, int(page), int(pageSize))
	if err != nil {
		return nil, status.Errorf(codes.Internal, "failed to get risk rules: %v", err)
	}

	// 转换为proto响应格式
	protoRules := make([]*__.RiskControlRule, 0, len(rules))
	for _, rule := range rules {
		protoRule := convertRiskRuleToProto(rule)
		protoRules = append(protoRules, protoRule)
	}

	// 计算总页数
	totalPage := int32((total + int64(pageSize) - 1) / int64(pageSize))

	return &__.GetRiskRulesResp{
		Rules: protoRules,
		Pagination: &__.PaginationResp{
			Total:     total,
			Page:      page,
			PageSize:  pageSize,
			TotalPage: totalPage,
		},
	}, nil
}

// convertRiskRuleToProto 将模型转换为proto格式
func convertRiskRuleToProto(rule *models.RiskControlRule) *__.RiskControlRule {
	protoRule := &__.RiskControlRule{
		Id:          uint64(rule.ID),
		Name:        rule.Name,
		Description: rule.Description,
		Priority:    rule.Priority,
		Scene:       rule.Scene,
		IsActive:    rule.IsActive,
		CreatedAt:   rule.CreatedAt.Format("2006-01-02 15:04:05"),
		UpdatedAt:   rule.UpdatedAt.Format("2006-01-02 15:04:05"),
	}
	return protoRule
}

// GetRiskRules 获取风控规则列表
func GetRiskRules(ctx context.Context, name, status, priority, scene string, page, pageSize int) ([]*models.RiskControlRule, int64, error) {
	var rules []*models.RiskControlRule
	var total int64

	query := config.DB.Model(&models.RiskControlRule{})

	// 添加筛选条件
	if name != "" {
		query = query.Where("name LIKE ?", "%"+name+"%")
	}

	if status != "" && status != "all" {
		isActive := status == "active"
		query = query.Where("is_active = ?", isActive)
	}

	if priority != "" && priority != "all" {
		query = query.Where("priority = ?", priority)
	}

	if scene != "" && scene != "all" {
		query = query.Where("scene = ?", scene)
	}

	// 计算总数
	query.Count(&total)

	// 分页查询
	offset := (page - 1) * pageSize
	err := query.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&rules).Error

	return rules, total, err
}

// GetRiskRuleProto 获取单个风控规则（Proto接口）
func GetRiskRuleProto(ctx context.Context, req *__.GetRiskRuleReq) (*__.GetRiskRuleResp, error) {
	// 参数验证
	if req.Id == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "rule id is required")
	}

	// 调用现有方法
	rule, err := GetRiskRule(ctx, int(req.Id))
	if err != nil {
		return nil, status.Errorf(codes.NotFound, "risk rule not found: %v", err)
	}

	return &__.GetRiskRuleResp{Rule: convertRiskRuleToProto(rule)}, nil
}

// GetRiskRule 获取单个风控规则
func GetRiskRule(ctx context.Context, id int) (*models.RiskControlRule, error) {
	var rule models.RiskControlRule
	err := config.DB.Where("id = ?", id).First(&rule).Error
	if err != nil {
		return nil, err
	}

	return &rule, nil
}

// CreateRiskRuleProto 创建风控规则（Proto接口）
func CreateRiskRuleProto(ctx context.Context, req *__.CreateRiskRuleReq) (*__.CreateRiskRuleResp, error) {
	// 参数验证
	if req.Rule == nil {
		return nil, status.Errorf(codes.InvalidArgument, "rule data is required")
	}
	if req.Rule.Name == "" {
		return nil, status.Errorf(codes.InvalidArgument, "rule name is required")
	}
	if req.Rule.Scene == "" {
		return nil, status.Errorf(codes.InvalidArgument, "rule scene is required")
	}
	if req.Rule.Priority == "" {
		return nil, status.Errorf(codes.InvalidArgument, "rule priority is required")
	}
	if len(req.Rule.Conditions) == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "rule must have at least one condition")
	}
	if len(req.Rule.Actions) == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "rule must have at least one action")
	}

	// 转换条件和动作到JSON字符串
	conditionsJSON, err := json.Marshal(req.Rule.Conditions)
	if err != nil {
		return nil, status.Errorf(codes.InvalidArgument, "invalid conditions format: %v", err)
	}

	actionsJSON, err := json.Marshal(req.Rule.Actions)
	if err != nil {
		return nil, status.Errorf(codes.InvalidArgument, "invalid actions format: %v", err)
	}

	// 创建模型对象
	rule := &models.RiskControlRule{
		Name:        req.Rule.Name,
		Description: req.Rule.Description,
		Priority:    req.Rule.Priority,
		Scene:       req.Rule.Scene,
		Conditions:  string(conditionsJSON),
		Actions:     string(actionsJSON),
		IsActive:    req.Rule.IsActive,
	}

	// 调用现有方法
	if err := CreateRiskRule(ctx, rule); err != nil {
		return nil, status.Errorf(codes.Internal, "failed to create risk rule: %v", err)
	}

	return &__.CreateRiskRuleResp{Rule: convertRiskRuleToProto(rule)}, nil
}

// CreateRiskRule 创建风控规则
func CreateRiskRule(ctx context.Context, rule *models.RiskControlRule) error {
	return config.DB.Transaction(func(tx *gorm.DB) error {
		// 创建规则
		if err := tx.Create(rule).Error; err != nil {
			return err
		}

		// 解析并创建条件
		var conditions []models.RuleCondition
		if err := json.Unmarshal([]byte(rule.Conditions), &conditions); err == nil {
			for i := range conditions {
				conditions[i].RuleID = strconv.Itoa(rule.ID)
				if err := tx.Create(&conditions[i]).Error; err != nil {
					return err
				}
			}
		}

		// 解析并创建动作
		var actions []models.RuleAction
		if err := json.Unmarshal([]byte(rule.Actions), &actions); err == nil {
			for i := range actions {
				actions[i].RuleID = strconv.Itoa(rule.ID)
				if err := tx.Create(&actions[i]).Error; err != nil {
					return err
				}
			}
		}

		return nil
	})
}

// UpdateRiskRuleProto 更新风控规则（Proto接口）
func UpdateRiskRuleProto(ctx context.Context, req *__.UpdateRiskRuleReq) (*__.UpdateRiskRuleResp, error) {
	// 参数验证
	if req.Rule == nil {
		return nil, status.Errorf(codes.InvalidArgument, "rule data is required")
	}
	if req.Rule.Id == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "rule id is required")
	}
	if req.Rule.Name == "" {
		return nil, status.Errorf(codes.InvalidArgument, "rule name is required")
	}
	if req.Rule.Scene == "" {
		return nil, status.Errorf(codes.InvalidArgument, "rule scene is required")
	}
	if req.Rule.Priority == "" {
		return nil, status.Errorf(codes.InvalidArgument, "rule priority is required")
	}
	if len(req.Rule.Conditions) == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "rule must have at least one condition")
	}
	if len(req.Rule.Actions) == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "rule must have at least one action")
	}

	// 转换条件和动作到JSON字符串
	conditionsJSON, err := json.Marshal(req.Rule.Conditions)
	if err != nil {
		return nil, status.Errorf(codes.InvalidArgument, "invalid conditions format: %v", err)
	}

	actionsJSON, err := json.Marshal(req.Rule.Actions)
	if err != nil {
		return nil, status.Errorf(codes.InvalidArgument, "invalid actions format: %v", err)
	}

	// 创建模型对象
	rule := &models.RiskControlRule{
		ID:          int(req.Rule.Id),
		Name:        req.Rule.Name,
		Description: req.Rule.Description,
		Priority:    req.Rule.Priority,
		Scene:       req.Rule.Scene,
		Conditions:  string(conditionsJSON),
		Actions:     string(actionsJSON),
		IsActive:    req.Rule.IsActive,
	}

	// 调用现有方法
	if err := UpdateRiskRule(ctx, rule); err != nil {
		return nil, status.Errorf(codes.Internal, "failed to update risk rule: %v", err)
	}

	return &__.UpdateRiskRuleResp{Rule: convertRiskRuleToProto(rule)}, nil
}

// UpdateRiskRule 更新风控规则
func UpdateRiskRule(ctx context.Context, rule *models.RiskControlRule) error {
	return config.DB.Transaction(func(tx *gorm.DB) error {
		// 更新规则
		if err := tx.Save(rule).Error; err != nil {
			return err
		}

		// 删除旧的条件和动作
		if err := tx.Where("rule_id = ?", rule.ID).Delete(&models.RuleCondition{}).Error; err != nil {
			return err
		}

		if err := tx.Where("rule_id = ?", rule.ID).Delete(&models.RuleAction{}).Error; err != nil {
			return err
		}

		// 创建新的条件
		var conditions []models.RuleCondition
		if err := json.Unmarshal([]byte(rule.Conditions), &conditions); err == nil {
			for i := range conditions {
				conditions[i].RuleID = strconv.Itoa(rule.ID)
				if err := tx.Create(&conditions[i]).Error; err != nil {
					return err
				}
			}
		}

		// 创建新的动作
		var actions []models.RuleAction
		if err := json.Unmarshal([]byte(rule.Actions), &actions); err == nil {
			for i := range actions {
				actions[i].RuleID = strconv.Itoa(rule.ID)
				if err := tx.Create(&actions[i]).Error; err != nil {
					return err
				}
			}
		}

		return nil
	})
}

// DeleteRiskRuleProto 删除风控规则（Proto接口）
func DeleteRiskRuleProto(ctx context.Context, req *__.DeleteRiskRuleReq) (*__.DeleteRiskRuleResp, error) {
	// 参数验证
	if req.Id == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "rule id is required")
	}

	// 先检查规则是否存在
	_, err := GetRiskRule(ctx, int(req.Id))
	if err != nil {
		return nil, status.Errorf(codes.NotFound, "risk rule not found: %v", err)
	}

	// 调用现有方法
	if err := DeleteRiskRule(ctx, int(req.Id)); err != nil {
		return nil, status.Errorf(codes.Internal, "failed to delete risk rule: %v", err)
	}

	// 返回成功响应
	return &__.DeleteRiskRuleResp{
		Success: true,
	}, nil
}

// DeleteRiskRule 删除风控规则
func DeleteRiskRule(ctx context.Context, id int) error {
	return config.DB.Transaction(func(tx *gorm.DB) error {
		// 删除关联的条件和动作
		if err := tx.Where("rule_id = ?", id).Delete(&models.RuleCondition{}).Error; err != nil {
			return err
		}

		if err := tx.Where("rule_id = ?", id).Delete(&models.RuleAction{}).Error; err != nil {
			return err
		}

		// 删除规则本身
		return tx.Where("id = ?", id).Delete(&models.RiskControlRule{}).Error
	})
}

// ToggleRiskRuleStatusProto 切换风控规则状态（Proto接口）
func ToggleRiskRuleStatusProto(ctx context.Context, req *__.ToggleRiskRuleStatusReq) (*__.ToggleRiskRuleStatusResp, error) {
	// 参数验证
	if req.Id == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "rule id is required")
	}

	// 调用现有方法
	rule, err := ToggleRiskRuleStatus(ctx, int(req.Id), req.IsActive)
	if err != nil {
		return nil, status.Errorf(codes.NotFound, "risk rule not found: %v", err)
	}

	return &__.ToggleRiskRuleStatusResp{Rule: convertRiskRuleToProto(rule)}, nil
}

// ToggleRiskRuleStatus 切换风控规则状态
func ToggleRiskRuleStatus(ctx context.Context, id int, isActive bool) (*models.RiskControlRule, error) {
	var rule models.RiskControlRule
	if err := config.DB.Where("id = ?", id).First(&rule).Error; err != nil {
		return nil, err
	}

	rule.IsActive = isActive
	if err := config.DB.Save(&rule).Error; err != nil {
		return nil, err
	}

	return &rule, nil
}

// GetRiskLogsProto 获取风险日志（Proto接口）
func GetRiskLogsProto(ctx context.Context, req *__.GetRiskLogsReq) (*__.GetRiskLogsResp, error) {
	// 规范化分页参数
	page := req.Page
	if page <= 0 {
		page = 1
	}
	pageSize := req.PageSize
	if pageSize <= 0 {
		pageSize = 20
	} else if pageSize > 100 {
		pageSize = 100
	}

	// 调用现有方法
	logs, total, err := GetRiskLogs(ctx, uint(req.UserId), req.RuleName, req.TriggeredOnly, int(page), int(pageSize))
	if err != nil {
		return nil, status.Errorf(codes.Internal, "failed to get risk logs: %v", err)
	}

	// 转换为proto响应格式
	protoLogs := make([]*__.RiskLogInfo, 0, len(logs))
	for _, log := range logs {
		protoLogs = append(protoLogs, &__.RiskLogInfo{
			Id:                  uint64(log.ID),
			LogId:               log.LogID,
			RuleName:            log.RuleName,
			Scene:               log.Scene,
			UserId:              uint64(log.UserID),
			Username:            log.Username,
			Triggered:           log.Triggered,
			ExecutionResult:     log.ExecutionResult,
			TriggeredConditions: log.TriggeredConditions,
			ExecutedActions:     log.ExecutedActions,
			IpAddress:           log.IpAddress,
			ExtraData:           log.ExtraData,
			CreatedAt:           log.CreatedAt.Format("2006-01-02 15:04:05"),
		})
	}

	return &__.GetRiskLogsResp{
		Logs:  protoLogs,
		Total: total,
	}, nil
}

// GetRiskLogs 获取风控日志
func GetRiskLogs(ctx context.Context, userID uint, ruleName string, triggeredOnly bool, page, pageSize int) ([]*models.RiskLog, int64, error) {
	var logs []*models.RiskLog
	var total int64

	query := config.DB.Model(&models.RiskLog{})

	// 添加筛选条件
	if userID != 0 {
		query = query.Where("user_id = ?", userID)
	}

	if ruleName != "" {
		query = query.Where("rule_name LIKE ?", "%"+ruleName+"%")
	}

	if triggeredOnly {
		query = query.Where("triggered = ?", true)
	}

	// 计算总数
	query.Count(&total)

	// 分页查询
	offset := (page - 1) * pageSize
	err := query.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&logs).Error

	return logs, total, err
}

// CreateRiskLog 创建风控日志
func CreateRiskLog(ctx context.Context, log *models.RiskLog) error {
	return config.DB.Create(log).Error
}

// RiskCheckResult 风险检查结果
// 注意：在实际应用中，这个结构体可能已在其他地方定义
// 这里为了示例方便，先在这里定义
// 实际项目中需要确保没有重复定义

// RiskCheckResult 风险检查结果
// 如果这个结构体已在其他地方定义，请删除以下定义
type RiskCheckResult struct {
	IsRisky      bool                      `json:"is_risky"`
	RiskLevel    string                    `json:"risk_level"`
	MatchedRules []*models.RiskControlRule `json:"matched_rules"`
	BlockAction  bool                      `json:"block_action"`
	Message      string                    `json:"message"`
}

// ExecuteRiskCheckProto 执行风险检查（Proto接口）
func ExecuteRiskCheckProto(ctx context.Context, req *__.RiskCheckRequest) (*__.RiskCheckResponse, error) {
	// 参数验证
	if req.UserId == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "user id is required")
	}
	if req.Scene == "" {
		return nil, status.Errorf(codes.InvalidArgument, "scene is required")
	}
	if req.RiskData == nil {
		return nil, status.Errorf(codes.InvalidArgument, "risk data is required")
	}

	// 转换Proto数据结构到map
	riskData := make(map[string]interface{})
	for k, v := range req.RiskData {
		riskData[k] = v
	}

	// 调用现有方法
	result, err := ExecuteRiskCheck(ctx, int(req.UserId), req.Scene, riskData)
	if err != nil {
		return nil, status.Errorf(codes.Internal, "failed to execute risk check: %v", err)
	}

	// 转换触发的规则为字符串列表
	triggeredRules := make([]string, 0, len(result.MatchedRules))
	for _, rule := range result.MatchedRules {
		triggeredRules = append(triggeredRules, rule.Name)
	}

	// 构建动作列表
	actions := make([]string, 0)
	if result.BlockAction {
		actions = append(actions, "block")
	}
	if len(triggeredRules) > 0 {
		actions = append(actions, "alert")
	}

	return &__.RiskCheckResponse{
		RiskLevel:      result.RiskLevel,
		Blocked:        result.IsRisky && result.BlockAction,
		TriggeredRules: triggeredRules,
		Actions:        actions,
		Message:        result.Message,
		VerifyData:     make(map[string]string), // 可根据实际需求填充
	}, nil
}

// ExecuteRiskCheck 执行风险检查
func ExecuteRiskCheck(ctx context.Context, userId int, scene string, riskData map[string]interface{}) (*RiskCheckResult, error) {
	// 注意：这是一个示例实现，实际项目中需要根据业务逻辑实现
	// 1. 查询当前场景下的所有活跃规则
	// 2. 根据规则条件与风险数据进行匹配
	// 3. 生成风险检查结果

	// 这里仅返回模拟数据
	return &RiskCheckResult{
		IsRisky:      false,
		RiskLevel:    "low",
		MatchedRules: []*models.RiskControlRule{},
		BlockAction:  false,
		Message:      "Risk check passed",
	}, nil
}
